/* -*- c++ -*- */

#ifndef _LINKED_LIST_H_
#define _LINKED_LIST_H_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

template< class T, unsigned short int TAM_LL_CACHO>
class LL_Cacho {
 public:
  LL_Cacho(): _next( NULL) {};
  ~LL_Cacho() {
    delete _next;
  }
  void clear() {
    for( unsigned short int i = 0; i < TAM_LL_CACHO; i++)
      _d[ i] = ( T)0L;
    if ( _next) {
      _next->clear();
    }
  }
  
  // T &operator[]( const int index) {
  //   if ( index < TAM_LL_CACHO) {
  //     return _d[ index];
  //   } else {
  //     if ( !_next) {
  //       _next = new LL_Cacho< T, TAM_LL_CACHO>;
  //       // _next->clear();
  //     }
  //     return ( *_next)[ index - TAM_LL_CACHO];
  //   }
  // }

  // let's make it iterative
  T &operator[]( const unsigned int index) {
    LL_Cacho< T, TAM_LL_CACHO> *toca = this;
    unsigned int l_index = index;
    while ( l_index >= TAM_LL_CACHO) {
      l_index -= TAM_LL_CACHO;
      if ( !toca->_next) {
        toca->_next = new LL_Cacho< T, TAM_LL_CACHO>;
        // toca->_next->clear();
      }
      toca = toca->_next;
    }
    return toca->_d[ l_index];
  }

  // T *get_pointer( const int index/*, const bool init = false*/) {
  //   if ( index < TAM_LL_CACHO) {
  //     return &_d[ index];
  //   } else {
  //     if ( !_next) {
  //       _next = new LL_Cacho< T, TAM_LL_CACHO>;
  //       // if ( init) {
  //       //   _next->clear();
  //       // }
  //     }
  //     return _next->get_pointer( index - TAM_LL_CACHO);
  //   }
  // }

  // let's make it iterative
  T *get_pointer( const unsigned int index/*, const bool init = false*/) {
    LL_Cacho< T, TAM_LL_CACHO> *toca = this;
    unsigned int l_index = index;
    while ( l_index >= TAM_LL_CACHO) {
      l_index -= TAM_LL_CACHO;
      if ( !toca->_next) {
        toca->_next = new LL_Cacho< T, TAM_LL_CACHO>;
        // if ( init) {
        //   toca->_next->clear();
        // }
      }
      toca = toca->_next;
    }
    return &( toca->_d[ l_index]);
  }

  size_t memory_size() const {
    // size_t ret = sizeof( LL_Cacho< T, TAM_LL_CACHO> *);
    // ret += sizeof( T) * TAM_LL_CACHO;
    size_t ret = sizeof( *this); // takes into account the padding
    if ( _next){
      ret += _next->memory_size();
    }
    return ret;
  }
  
 private:
  LL_Cacho< T, TAM_LL_CACHO> *_next;
  T _d[ TAM_LL_CACHO];
};

template< class T, unsigned short int TAM_LL_CACHO>
class LinkedList {
 public:
  LinkedList( /*bool init = false*/): /*_init( init),*/ _size_used( 0) {
    // if ( init) {
    //   _head.clear();
    // }
  }
  // void set_init( bool init) { _init = init;}
  void clear() {
    _head.clear();
    _size_used = 0;
  }
  T &operator[]( const unsigned int index) {
    assert( index < _size_used);
    return _head[ index];
  }
  T *get_pointer( const unsigned int index) {
    if ( index < _size_used)
      return _head.get_pointer( index);
    else
      return NULL;
  }
  unsigned int size() const { return _size_used;}
  T *append( const T &item) {
    _head[ _size_used] = item;
    T *ret = _head.get_pointer( _size_used/*, _init*/);
    _size_used++;
    return ret;
  }
  size_t memory_size() const {
    // size_t ret = sizeof( unsigned int);
    size_t ret = sizeof( *this); // takes into account the padding
    ret -= sizeof( _head); // _head.memory_size() also counts itself
    ret += _head.memory_size();
    return ret;
  }
  
 private:
  LL_Cacho< T, TAM_LL_CACHO> _head;
  // bool _init;
  unsigned int _size_used;
  // unsigned int _fill_space[ 3];
};

#endif // _LINKED_LIST_H_
